%%%-------------------------------------------------------------------
%%% @author Rain
%%% @doc 帧同步回调模块
%%% @end
%%%-------------------------------------------------------------------
-module(lock_step_cb).
-author("Rain").
-behaviour(elock_step_behaviour).
-include("common.hrl").
-include("lock_step_cb.hrl").
-include("role.hrl").
-include_lib("elock_step/include/elock_step.hrl").
-include_lib("elock_step/include/ls_room_svr.hrl").
-include("lock_step_pb.hrl").

%% API
-export([call_client_match_fail/1]).
-export([call_client_match_succ/2]).
-export([call_client_room_not_find/3]).
-export([call_client_fight_start/4]).
-export([call_client_reconnect_succ/4]).
-export([call_client_check_hash_fail/3]).
-export([call_client_adjust_update_time/2]).
-export([call_client_one_frame_inputs/2]).
-export([call_client_match/2]).
-export([time_ms/0]).
-export([log/3]).
-export([calc_frame_hash_and_snapshots/2]).

-export([match_pool_name/1]).
-export([match_svr_child_spec/1]).

%% @doc 匹配池名字
match_pool_name(MatchType) ->
    list_to_atom("match_pool_" ++ integer_to_list(MatchType)).

%% @doc 匹配进程池的子进程描述
match_svr_child_spec(MatchType) ->
    PoolSize = match_pool_size(MatchType),
    OverflowSize = match_pool_size_overflow(MatchType),
    WorkerArgs = [{match_count, match_count(MatchType)}],
    PoolName = match_pool_name(MatchType),
    SizeArgs = [{size, PoolSize}, {max_overflow, OverflowSize}],
    PoolArgs = [{name, {local, PoolName}}, {worker_module, ls_match_svr}] ++ SizeArgs,
    ChildSpec = poolboy:child_spec(PoolName, PoolArgs, WorkerArgs),
    ChildSpec.

%% @doc 匹配的玩家人数
match_count(?LS_MATCH_TYPE_1V1) ->
    2.

%% @doc 匹配池的大小
match_pool_size(?LS_MATCH_TYPE_1V1) ->
    1.

%% @doc 匹配池溢出的大小
match_pool_size_overflow(?LS_MATCH_TYPE_1V1) ->
    1.


call_client_match(RoleId, ok) ->
    ?RID2C_MSG(RoleId, #lock_step_match_s2c{});
call_client_match(RoleId, {fail, already_in_match_queue}) ->
    ?RID2C_MSG(RoleId, #lock_step_match_s2c{code = 1}).

call_client_match_fail(RoleId) ->
    ?RID2C_MSG(RoleId, #lock_step_match_fail_s2c{}),
    ok.

call_client_match_succ(RoleId, MatchId) ->
    ?RID2C_MSG(RoleId, #lock_step_match_success_s2c{match_id = MatchId}),
    ok.

call_client_room_not_find(_RoleId, _MatchId, _Reason) ->
    ok.

call_client_fight_start(RoleId, StartTime, UnitInfos, RandomSeed) ->
    ?RID2C_MSG(RoleId, #lock_step_fight_start_s2c{start_time = StartTime, random_seed = RandomSeed,
        unit_infos = p_unit_infos(UnitInfos)}),
    ok.

call_client_reconnect_succ(_RoleId, _StartTime, _UnitInfos, _Frame) ->
    ok.

call_client_check_hash_fail(_RoleId, _Frame, _Units) ->
    ok.

call_client_adjust_update_time(_RoleId, _DiffTime) ->
    ok.

call_client_one_frame_inputs(RoleId, OneFrameInputs) ->
    ?RID2C_MSG(RoleId, #lock_step_one_frame_inputs_s2c{inputs = p_one_frame_inputs(OneFrameInputs)}),
    ok.

log(error, Format, Args) ->
    ?LOG_ERROR(Format, Args);
log(warn, Format, Args) ->
    ?LOG_WARN(Format, Args).

time_ms() ->
    game_util_time:now_ms().

calc_frame_hash_and_snapshots(Units, SnapShots) ->
    {Units, SnapShots}.


p_unit_infos(UnitInfos) ->
    p_unit_infos(UnitInfos, []).

p_unit_infos([], Acc) ->
    Acc;
p_unit_infos([#ls_unit_info{role_id = RoleId,
    position = #ls_pos_v3{x = PX, y = PY, z = PZ},
    rotation = #ls_rotation{x = RX, y = RY, z = RZ, w = RW}} | T], Acc) ->
    RandName = list_to_binary(peer:random_name()),
    Add = #p_lock_step_unit_info{role_id = RoleId, name = RandName,
        position = #p_true_sync_v3{x = PX, y = PY, z = PZ},
        rotation = #p_true_sync_quaternion{x = RX, y = RY, z = RZ, w = RW}
    },
    Acc1 = [Add | Acc],
    p_unit_infos(T, Acc1).

p_one_frame_inputs(OneFrameInputs) ->
    Fun =
        fun(RoleId, LsInput, Acc) ->
            #ls_input{button = Button} = LsInput,
        Add = #p_one_frame_input{role_id = RoleId, input =
                #p_ls_input{parameters = #p_ls_input_param{button = Button}}},
            [Add | Acc]
        end,
    maps:fold(Fun, [], OneFrameInputs).

